package com.adityayadav.anaida;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.StringTokenizer;

public class WebSocketAdapter {

	private IWebSocketListener listener = null;
	private String host="localhost";
	private int port=8080;
	private String path="/websocket";
	private HTTPRequestParser parser = new HTTPRequestParser();
	private Socket socket = null;
	private InputStream in = null;
	private OutputStream out = null;
	
	public static final byte WS_PACKET_START_BYTE = (byte)0x00;
	public static final byte WS_PACKET_END_BYTE = (byte) 0xff;
	public static final String US_ASCII_CHARSET = "US-ASCII";
	public static final String UTF8_CHARSET = "UTF-8";
	public static final byte[] separator = new byte[]{13,10};
	
	
	public static final int START_STATE = 0;
	public static final int PARSED_GET_STATE = 1;
	public static final int PARSED_HEADERS = 2;
	
	private int state = START_STATE;
	
	
	public WebSocketAdapter(String host, int port, String path, IWebSocketListener listener) throws Exception {
		this.path = path;
		this.port = port;
		this.host = host;
		this.listener = listener;
		
		socket = new Socket(host, port);
		in = socket.getInputStream();
		out = socket.getOutputStream();
		
		
		out.write("GET /websocket HTTP/1.1".getBytes(US_ASCII_CHARSET));
		out.write(separator);
		out.write("Upgrade: WebSocket".getBytes(US_ASCII_CHARSET));
		out.write(separator);
		out.write("Connection: Upgrade".getBytes(US_ASCII_CHARSET));
		out.write(separator);
		out.write(("Host: "+host+":"+port).getBytes(US_ASCII_CHARSET));
		out.write(separator);
		out.write(("Origin: http://"+host+":"+port).getBytes(US_ASCII_CHARSET));
		out.write(separator);
		out.write("Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5".getBytes(US_ASCII_CHARSET));
		out.write(separator);
		out.write("Sec-WebSocket-Key2: 4 @2  43485xW%0l 2 3".getBytes(US_ASCII_CHARSET));
		out.write(separator);
		out.write(separator);
		out.write(new byte[]{23,45,34,56,45,56,56,67});
		out.flush();
		
		
		
		
		Thread t = new Thread(){
			public void run(){
				try {
					// recieve handshake
					byte[] readBuffer = new byte[8192];
					int numRead = 0;
					while (true){
						numRead = in.read(readBuffer);
						if (numRead == -1) {
							System.out.println("Read -1");
							closeAdapter();
							return;
						}
						
						if (numRead >=0){
							byte[] message = new byte[numRead];
						    System.arraycopy(readBuffer, 0, message, 0, numRead);
							parser.addToBuffer(message);
							
							byte[] line = null;
							while ((line = parser.getALine())!= null){
								
								switch(state){
								case START_STATE:
									state = PARSED_GET_STATE;
									break;
								case PARSED_GET_STATE:
									processHeader(line);
									break;
								case PARSED_HEADERS:
									handleWebSocketFrames(line);
									break;
								}
							}
						}
					}
				} catch (Exception e){
					closeAdapter();
				}
			}

			
		};
		t.start();
	}
	
	private void processHeader(byte[] line)throws Exception{
		if (line.length ==0){
			state = PARSED_HEADERS;
			/*byte[] readBuffer = new byte[8192];
			while(true){
				if (parser.getBuffer().length <16){
					int numRead = 0;
					numRead = in.read(readBuffer);
					if (numRead == -1) {
						closeAdapter();
						return;
					}
						
					if (numRead >=0){
						byte[] message = new byte[numRead];
					    System.arraycopy(readBuffer, 0, message, 0, numRead);
						parser.addToBuffer(message);
					}
				}else {
					parser.getNBytes(16,new byte[0]);
					break;
				}
			}*/
			parser.getNBytes(16,new byte[0]);
			parser.setSeparator(new byte[]{WS_PACKET_END_BYTE});
			if (listener != null) listener.onopen();
		}
	}
	
	private void handleWebSocketFrames(byte[] packet) throws Exception {
    	
		
    	byte[] rawpacket = new byte[packet.length-1];
    	System.arraycopy(packet,1,rawpacket,0,rawpacket.length);
    	
    	if (listener != null) listener.onmessage(rawpacket);
    }
	
	private void closeAdapter() {
		if (WebSocketAdapter.this.listener != null) WebSocketAdapter.this.listener.onclose();
		try {
			in.close();
		} catch (Exception f){}
		try {
			out.close();
		} catch (Exception f){}
		try {
			socket.close();
		} catch (Exception f){}
	}
	
	public void send(byte[] message) throws Exception {
		try {
			out.write(new byte[]{WS_PACKET_START_BYTE});
			out.write(message);
			out.write(new byte[]{WS_PACKET_END_BYTE});
		}catch (Exception e){
			closeAdapter();
			throw e;
		}
	}
	
}
